package at.ac.tuwien.dse.health.event.bus;

import org.springframework.util.MethodInvoker;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

/**
 * Invokes a certain method using given parameters via reflection.
 *
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 */
public class EventTarget extends MethodInvoker {
	public EventTarget(Object target, Method method) {
		setTargetObject(target);
		setTargetMethod(method.getName());
	}

	/**
	 * Invokes the method with the given arguments.
	 * <p/>
	 * Before invoking the method, the method invokation is prepared i.e., by appliying parameters and resolving
	 * the method if necessary. Afterwards, the arguments are reset so that this instance can be reused without
	 * possible side-effects.
	 * <p/>
	 * <b>Note that this method is not thread-safe. Thus the caller must ensure that this method must not be
	 * invoked concurrently.</b>
	 *
	 * @param args the arguments to pass
	 * @see #setArguments(Object[])
	 * @see #prepare()
	 * @see #invoke()
	 */
	public void invoke(Object... args) {
		setArguments(args);
		try {
			if (!isPrepared()) {
				prepare();
			}
			invoke();
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		} finally {
			setArguments(null);
		}
	}

	@Override
	public String toString() {
		return getTargetClass().getName() + "." + getTargetMethod();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		EventTarget that = (EventTarget) o;

		if (!getTargetMethod().equals(that.getTargetMethod())) return false;
		if (!getTargetObject().equals(that.getTargetObject())) return false;

		return true;
	}

	@Override
	public int hashCode() {
		int result = getTargetObject().hashCode();
		result = 31 * result + getTargetMethod().hashCode();
		return result;
	}
}
